/**
 * 
 */
package edu.rit.cs.core.services.daos.impl;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Restrictions;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import edu.rit.cs.core.services.daos.GenericDAO;

/**
 * Implements the common methods to interact with the database, so that children
 * classes don't need to implement them.
 * 
 * @author Abhishek Shrestha (axs1430)
 * @author Juan Saldana (jjs6109)
 * @author Victor Alvarez (vxa1557)
 */
@SuppressWarnings("unchecked")
public class GenericDAOImpl<T, ID extends Serializable> implements GenericDAO<T, ID> {
  private static final long serialVersionUID = 1L;

  private Class<T> persistentClass;
  private SessionFactory sessionFactory;

  public GenericDAOImpl() {
    this.persistentClass = (Class<T>) ((ParameterizedType) getClass()
            .getGenericSuperclass()).getActualTypeArguments()[0];

  }

  public void setSessionFactory(final SessionFactory session) {
    this.sessionFactory = session;
  }

  protected SessionFactory getSessionFactory() {
    return this.sessionFactory;
  }

  @Transactional(propagation = Propagation.SUPPORTS)
  @Override
  public T findById(ID id) {
    Criteria c = sessionFactory.getCurrentSession().createCriteria(persistentClass);
    c.add(Restrictions.eq("id", id));
    return (T) c.uniqueResult();
  }

  protected Class<T> getPersistentClass() {
    return this.persistentClass;
  }

  @Transactional(propagation = Propagation.REQUIRED)
  @Override
  public T save(T object) {
    sessionFactory.getCurrentSession().saveOrUpdate(object);
    return object;
  }

  @Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
  @Override
  public List<T> findAll() {
    return (List<T>) sessionFactory.getCurrentSession().createCriteria(persistentClass).list();
  }
}
